package gov.fnal.mcginnis.fitstest;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import nom.tam.fits.Fits;
import nom.tam.fits.FitsException;
import nom.tam.fits.Header;
import nom.tam.fits.HeaderCard;
import nom.tam.fits.ImageHDU;
import nom.tam.image.ImageTiler;
import nom.tam.util.BufferedFile;

/**
 * @author mcginnis
 *
 */
public class PixieImage 
{
	private double[][] pix = null;
	/**
	 * 
	 */
	public Header header = null;
	PixieImage()
	{
		pix = null;
		header = null;
		header = new Header();
	}
	PixieImage(PixieImage pi)
	{
		this();
		int	ii, ij;
		int	nrow = 0;
		int ncol = 0;
		nrow = pi.getRowCount();
		ncol = pi.getColCount();
		if ((nrow > 0) && (ncol > 0))
		{
			pix = new double[nrow][ncol];
			for (ii = 0; ii < nrow; ++ii)
			{
				for (ij = 0; ij < ncol; ++ij)
				{
					pix[ii][ij] = pi.pix[ii][ij];
				}
			}
		}
        copyHeaderCards(pi.header);

	}
	PixieImage(int nrow, int ncol)
	{
		this();
		int	ii, ij;
		if ((nrow > 0) && (ncol > 0))
		{
			pix = new double[nrow][ncol];
			for (ii = 0; ii < nrow; ++ii)
			{
				for (ij = 0; ij < ncol; ++ij)
				{
					pix[ii][ij] = 0.0;
				}
			}
		}
	}
	PixieImage(String fitsFileName) throws FitsException, IOException 
	{
		this();
		Fits fits = new Fits(fitsFileName);
		ImageHDU hdu = (ImageHDU) fits.readHDU();
        Header hdr = hdu.getHeader();
		if (hdr.getIntValue("NAXIS") != 2) 
		{
			fits = null;
			hdu = null;
			hdr = null;
			throw  new FitsException(); 
		}
		if (hdr.getIntValue("BITPIX") != -32) 
		{
			fits = null;
			hdu = null;
			hdr = null;
			throw  new FitsException(); 
		}
		float[][] image = (float[][]) hdu.getData().getKernel();
		int ii, ij;
		int nrow = image.length;
		int ncol = image[0].length;
		pix = new double[nrow][ncol];
		for (ii = 0; ii < nrow; ++ii)
		{
			for (ij = 0; ij < ncol; ++ij)
			{
				pix[ii][ij] = (double) image[ii][ij];
			}
		}
        copyHeaderCards(hdu.getHeader());
		fits = null;
		hdu = null;
		hdr = null;
		image = null;
	}
	PixieImage(File fitsFile) throws FitsException, IOException
	{
		this(fitsFile.getPath());
	}
	PixieImage(String fitsFileName, int startRow, int startCol, int nrows, int ncols) throws FitsException, IOException 
	{
		this();
		Fits fits = new Fits(fitsFileName);
		ImageHDU hdu = (ImageHDU) fits.readHDU();
        Header hdr = hdu.getHeader();
		int maxRows = hdr.getIntValue("NAXIS2");
		int maxCols = hdr.getIntValue("NAXIS1");
		boolean goodParam = true;
		if (startRow > (maxRows - 1)) goodParam = false;
		if (startCol > (maxCols - 1)) goodParam = false;
		if (hdr.getIntValue("NAXIS") != 2) goodParam = false;
		if (hdr.getIntValue("BITPIX") != -32) goodParam = false;
		if(!goodParam)
		{
			fits = null;
			hdu = null;
			hdr = null;
			throw  new FitsException(); 
		}
		if(startRow < 0) startRow = 0;
		if(startCol < 0) startCol = 0;
		if ((startRow + nrows) > maxRows) nrows = maxRows - startRow;
		if ((startCol + ncols) > maxCols) ncols = maxCols - startCol;
		ImageTiler imageTiler = hdu.getTiler();
		float[] tile = new float[nrows * ncols];
		imageTiler.getTile(tile, new int[]{startRow,startCol}, new int[]{nrows,ncols});
		pix = new double[nrows][ncols];
		for (int ii = 0; ii < ncols; ++ii) 
		{
		    for (int ij = 0; ij < nrows; ++ij) 
		    {
		    	pix[ij][ii] = (double) tile[ii + ij * ncols];
		    }
		}
        copyHeaderCards(hdu.getHeader());
		fits = null;
		hdu = null;
		hdr = null;
		imageTiler = null;
		tile = null;
	}
	PixieImage(File fitsFile, int startRow, int startCol, int nrows, int ncols) throws FitsException, IOException 
	{
		this(fitsFile.getPath(), startRow, startCol, nrows, ncols);
	}
	/**
	 * @return
	 */
	public int getRowCount()
	{
		int nrow = 0;
		if (pix != null)
		{
			nrow = pix.length;
		}
		return	nrow;
	}
	/**
	 * @param fitsFileName
	 * @return
	 * @throws FitsException
	 * @throws IOException
	 */
	public static int getRowCount(String fitsFileName) throws FitsException, IOException
	{
		Fits fits = new Fits(fitsFileName);
		ImageHDU hdu = (ImageHDU) fits.readHDU();
        Header hdr = hdu.getHeader();
		int maxRows = hdr.getIntValue("NAXIS2");
		fits = null;
		hdu = null;
		hdr = null;
		return maxRows;
	}
	/**
	 * @param fitsFile
	 * @return
	 * @throws FitsException
	 * @throws IOException
	 */
	public static int getRowCount(File fitsFile) throws FitsException, IOException
	{
		return getRowCount(fitsFile.getPath());
	}
	/**
	 * @param fitsFileName
	 * @return
	 * @throws FitsException
	 * @throws IOException
	 */
	public static int getColCount(String fitsFileName) throws FitsException, IOException
	{
		Fits fits = new Fits(fitsFileName);
		ImageHDU hdu = (ImageHDU) fits.readHDU();
        Header hdr = hdu.getHeader();
		int maxCols = hdr.getIntValue("NAXIS1");
		fits = null;
		hdu = null;
		hdr = null;
		return maxCols;
	}
	/**
	 * @param fitsFile
	 * @return
	 * @throws FitsException
	 * @throws IOException
	 */
	public static int getColCount(File fitsFile) throws FitsException, IOException
	{
		return getColCount(fitsFile.getPath());
	}
	/**
	 * @return
	 */
	public int getColCount()
	{
		int ncol = 0;
		if (pix != null)
		{
			ncol = pix[0].length;
		}
		return	ncol;
	}
	/**
	 * @return
	 */
	public double[][] getPix()
	{
		return pix;
	}
	/**
	 * @param headerIn
	 */
	public void copyHeaderCards(Header headerIn) 
	{
		Iterator it = headerIn.iterator();
		while (it.hasNext()) {
			HeaderCard headerCard = (HeaderCard) it.next();
			header.addLine(headerCard);
		}
	}
	private void appendHeaderCards(Header headerOut, Header headerIn)
	{
		Iterator it = headerIn.iterator();
		boolean okayCardToAdd = true;
		while (it.hasNext()) 
		{
			HeaderCard headerCard = (HeaderCard) it.next();
			okayCardToAdd = true;
			if( headerCard.getKey().equals("SIMPLE")) okayCardToAdd = false;
			if( headerCard.getKey().equals("BITPIX")) okayCardToAdd = false;
			if( headerCard.getKey().equals("NAXIS")) okayCardToAdd = false;
			if( headerCard.getKey().equals("NAXIS1")) okayCardToAdd = false;
			if( headerCard.getKey().equals("NAXIS2")) okayCardToAdd = false;
			if( headerCard.getKey().equals("EXTEND")) okayCardToAdd = false;
			if (okayCardToAdd) headerOut.addLine(headerCard);
		}
	}
	/**
	 * @param fitsFileName
	 * @throws FitsException
	 * @throws IOException
	 */
	public void writeToFitsFile(String fitsFileName)  throws FitsException, IOException
	{
		if (pix == null) throw new FitsException();
		int nrow = pix.length;
		int ncol = pix[0].length;
		float[][] image = new float[nrow][ncol];
		for (int ii = 0; ii < nrow; ++ii)
		{
			for (int ij = 0; ij < ncol; ++ij)
			{
				image[ii][ij] = (float) pix[ii][ij];
			}
		}

		Fits fits = new Fits();
		ImageHDU hdu = (ImageHDU) Fits.makeHDU(image);
		Header hdr = hdu.getHeader();
		appendHeaderCards(hdr, header);
		fits.addHDU(hdu);
		BufferedFile bf = new BufferedFile(fitsFileName, "rw");
		fits.write(bf);
		bf.flush();
		bf.close();
		bf = null;
		fits = null;
		image = null;
		hdu = null;
	}
	/**
	 * @param fitsFile
	 * @throws FitsException
	 * @throws IOException
	 */
	public void writeToFitsFile(File fitsFile)  throws FitsException, IOException
	{
		writeToFitsFile(fitsFile.getPath());
	}
}
